package com.crazymakercircle.reactormodel;


import com.crazymakercircle.util.Logger;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.concurrent.*;

/**
 * @author admin
 */
public class MultiThreadEchoHandler implements Runnable {
    private final SocketChannel channel;
    private final SelectionKey selectionKey;
    final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    private static final int RECIEVING = 0;
    private static final int SENDING = 1;
    private int state = RECIEVING;
    private static ExecutorService pool = new ThreadPoolExecutor(4,
            4,
            0,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>());

    public MultiThreadEchoHandler(Selector selector, SocketChannel socketChannel) throws IOException {
        channel = socketChannel;
        socketChannel.configureBlocking(false);
        selectionKey = channel.register(selector, 0);
        selectionKey.attach(this);
        selectionKey.interestOps(SelectionKey.OP_READ);
        selector.wakeup();
    }

    @Override
    public void run() {
        pool.execute(() -> asyncRun());
    }

    /**
     * 异步任务，不在Reactor线程中执行
     */
    private synchronized void asyncRun() {
        try {
            if (state == SENDING) {
                channel.write(byteBuffer);
                byteBuffer.clear();
                selectionKey.interestOps(SelectionKey.OP_READ);
                state = RECIEVING;
            } else if (state == RECIEVING) {
                int length;
                while ((length = channel.read(byteBuffer)) > 0) {
                    Logger.info(new String(byteBuffer.array(), 0, length));
                }
                byteBuffer.flip();
                selectionKey.interestOps(SelectionKey.OP_WRITE);
                state = SENDING;
            }
            //处理结束了, 这里不能关闭select key，需要重复使用
            //selectionKey.cancel();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}

